#region Microsoft Public License
/*
 * (c) Copyright Chenjun Wu. http://utablesdk.codeplex.com
 * 
 * This source is subject to the Microsoft Public License (Ms-PL).
 * Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
 * All other rights reserved.
 */
#endregion

﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls.Primitives;
using System.Windows;
using System.Windows.Controls;
using System.ComponentModel;

namespace UTable.Objects.Controls.Primitives
{
    public class UPopup : UContentControl
    {
		public UPopup()
		{
			Close();
			this.Loaded += new RoutedEventHandler(UPopup_Loaded);
		}

		void UPopup_Loaded(object sender, RoutedEventArgs e)
		{

		}

        #region Properties

        public bool IsOpen
        {
            get 
            {
                return (bool)GetValue(IsOpenProperty); 
            }
            set 
            { 
                SetValue(IsOpenProperty, value); 
            }
        }

        public static readonly DependencyProperty IsOpenProperty =
			DependencyProperty.Register("IsOpen", typeof(bool), typeof(UPopup), 
			new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnIsOpenChanged)));

		/// <summary>
		///		Gets or sets the element relative to which the UTable.Objects.Controls.Primitives.UPopup 
		///     is positioned when it opens. This is a dependency property. 
		/// </summary>
		public FrameworkElement PlaceTarget
		{
			get { return (FrameworkElement)GetValue(PlaceTargetProperty); }
			set { SetValue(PlaceTargetProperty, value); }
		}

		public static readonly DependencyProperty PlaceTargetProperty =
			DependencyProperty.Register("PlaceTarget", typeof(FrameworkElement), typeof(UPopup), new UIPropertyMetadata(null));


		/// <summary>
		/// Gets or sets the orientation of the UTable.Objects.Controls.Primitives.UPopup
		/// control when the control opens, and specifies the behavior of the UTable.Objects.Controls.Primitives.UPopup
		/// control when it overlaps screen boundaries. This is a dependency property.
		/// </summary>
		public PlacementMode Placement
		{
			get { return (PlacementMode)GetValue(PlacementProperty); }
			set { SetValue(PlacementProperty, value); }
		}

		public static readonly DependencyProperty PlacementProperty =
			DependencyProperty.Register("Placement", typeof(PlacementMode), typeof(UPopup), new UIPropertyMetadata(PlacementMode.Absolute));

		public double HorizontalOffset
		{
			get { return (double)GetValue(HorizontalOffsetProperty); }
			set { SetValue(HorizontalOffsetProperty, value); }
		}

		public static readonly DependencyProperty HorizontalOffsetProperty =
			DependencyProperty.Register("HorizontalOffset", typeof(double), typeof(UPopup), new UIPropertyMetadata(0.0));

		public double VerticalOffset
		{
			get { return (double)GetValue(VerticalOffsetProperty); }
			set { SetValue(VerticalOffsetProperty, value); }
		}

		public static readonly DependencyProperty VerticalOffsetProperty =
			DependencyProperty.Register("VerticalOffset", typeof(double), typeof(UPopup), new UIPropertyMetadata(0.0));

		public bool AllowsTransparency
		{
			get { return (bool)GetValue(AllowsTransparencyProperty); }
			set { SetValue(AllowsTransparencyProperty, value); }
		}

		public static readonly DependencyProperty AllowsTransparencyProperty =
			DependencyProperty.Register("AllowsTransparency", typeof(bool), typeof(UPopup), new UIPropertyMetadata(true));

		public PopupAnimation PopupAnimation
		{
			get { return (PopupAnimation)GetValue(PopupAnimationProperty); }
			set { SetValue(PopupAnimationProperty, value); }
		}

		public static readonly DependencyProperty PopupAnimationProperty =
			DependencyProperty.Register("PopupAnimation", typeof(PopupAnimation), typeof(UPopup), new UIPropertyMetadata(PopupAnimation.None));



		public bool HasDropShadow
		{
			get { return (bool)GetValue(HasDropShadowProperty); }
			set { SetValue(HasDropShadowProperty, value); }
		}

		public static readonly DependencyProperty HasDropShadowProperty =
			DependencyProperty.Register("HasDropShadow", typeof(bool), typeof(UPopup), new UIPropertyMetadata(false));

        #endregion

		#region Methods

		public override void OnApplyTemplate()
		{
			base.OnApplyTemplate();
		}

		public static void OnIsOpenChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
		{
			UPopup popup = obj as UPopup;
			if (popup != null)
			{
				if ((bool)args.NewValue)
				{
					popup.Open();
				}
				else
				{
					popup.Close();
				}
			}
		}

		private void Open()
		{
			if (!DesignerProperties.GetIsInDesignMode(this))
			{
				SetParent();
			}

			PositionPopup();
			this.Visibility = Visibility.Visible;

			OnOpend(EventArgs.Empty);
			if (Opened != null)
				Opened(this, EventArgs.Empty);
		}

		private void Close()
		{
			this.Visibility = Visibility.Collapsed;

			OnClosed(EventArgs.Empty);
			if (Closed != null)
				Closed(this, EventArgs.Empty);
		}

		public void PositionPopup()
		{
			Canvas popupStage = (UTableHelper.CurrentVisualTree as UObject).PopupStage;
			Point relativePoint = new Point(0, 0);
			if (PlaceTarget != null)
				relativePoint = PlaceTarget.TranslatePoint(new Point(0, 0), popupStage);
			// Canvas.SetRight(this, 0);
			// Canvas.SetBottom(this, 0);
			PlacementMode placement = this.Placement;
			if (this.PlaceTarget == null)
				placement = PlacementMode.Absolute;
			switch (placement)
			{
				case PlacementMode.Absolute:
					Canvas.SetLeft(this, AlignWithEdge(HorizontalOffset));
					Canvas.SetTop(this, AlignWithEdge(VerticalOffset));
					break;
				case PlacementMode.Relative:
					Canvas.SetLeft(this, AlignWithEdge(HorizontalOffset + relativePoint.X));
					Canvas.SetTop(this, AlignWithEdge(VerticalOffset + relativePoint.Y));
					break;
				case PlacementMode.Left:
					Canvas.SetLeft(this, AlignWithEdge(relativePoint.X - this.Width));
					Canvas.SetTop(this, AlignWithEdge(relativePoint.Y));
					break;
				case PlacementMode.Top:
					Canvas.SetLeft(this, AlignWithEdge(relativePoint.X));
					Canvas.SetTop(this, AlignWithEdge(relativePoint.Y - this.Height));
					break;
				case PlacementMode.Right:
					Canvas.SetLeft(this, AlignWithEdge(relativePoint.X + PlaceTarget.ActualWidth));
					Canvas.SetTop(this, AlignWithEdge(relativePoint.Y));
					break;
				case PlacementMode.Bottom:
					Canvas.SetLeft(this, AlignWithEdge(relativePoint.X));
					Canvas.SetTop(this, AlignWithEdge(relativePoint.Y + PlaceTarget.ActualHeight));
					break;
				case PlacementMode.Center:
					Canvas.SetLeft(this, AlignWithEdge(relativePoint.X + (PlaceTarget.ActualWidth - this.Width) / 2));
					Canvas.SetTop(this, AlignWithEdge(relativePoint.Y + (PlaceTarget.ActualHeight - this.Height) / 2));
					break;
			}
		}

		private double AlignWithEdge(double v)
		{
			if (v >= 0)
				return v;
			else
				return 0;
		}

		private void SetParent()
		{
            if (!(UTableHelper.CurrentVisualTree is UObject))
                return;

			Canvas popupStage = (UTableHelper.CurrentVisualTree as UObject).PopupStage;
			if (!popupStage.Children.Contains(this))
			{
				DependencyObject obj = this.Parent;

				if (obj != null)
				{
					if (obj is ContentControl)
					{
						(obj as ContentControl).Content = null;
					}
					else if (obj is Decorator)
					{
						(obj as Decorator).Child = null;
					}
					else if (obj is Panel)
					{
						(obj as Panel).Children.Remove(this);
					}
					if (this.PlaceTarget == null && obj is FrameworkElement)
						this.PlaceTarget = obj as FrameworkElement;
				}
				else
				{
					this.PlaceTarget = UTableHelper.CurrentVisualTree as UObject;
				}

				popupStage.Children.Add(this);
			}
		}

		protected virtual void OnOpend(EventArgs e)
		{

		}

		protected virtual void OnClosed(EventArgs e)
		{

		}

		protected override DependencyObject GetUIParentCore()
		{
			return base.GetUIParentCore();
		}

		#endregion

		#region Events

		public event EventHandler Opened;

		public event EventHandler Closed;

		#endregion
	}
}
